package com.vcc.service.impl;


import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.vcc.core.util.DateUtil;
import com.vcc.core.util.IpUtil;
import com.vcc.core.util.RegexUtil;
import com.vcc.data.entity.Role;
import com.vcc.data.entity.WalletDetail;
import com.vcc.data.mapper.WalletDetailMapper;
import com.vcc.service.boss.response.walletDetail.WalletDetailVoBoss;
import com.vcc.service.sa.BossUserUtil;
import com.vcc.service.service.UserCardService;
import com.vcc.service.service.UserService;
import com.vcc.service.service.WalletDetailService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static com.vcc.data.entity.table.BossUserTableDef.BOSS_USER;
import static com.vcc.data.entity.table.UserTableDef.USER;
import static com.vcc.data.entity.table.WalletDetailTableDef.WALLET_DETAIL;

@Service
public class WalletDetailServiceImpl extends ServiceImpl<WalletDetailMapper, WalletDetail> implements WalletDetailService {

    @Autowired
    private UserService userService;
    @Autowired
    private UserCardService userCardService;

    @Override
    public Page<WalletDetail> paging(
            Page<WalletDetail> pageable,
            Role role,
            Long userId,
            Long targetUserId,
            String cardNumber,
            Integer useFlag,
            String startDate,
            String endDate,
            String remark,
            String orderId) {
        QueryChain<WalletDetail> queryChain = queryChain();
        if (role.getHasAllData()) {
            queryChain.leftJoin(USER).on(USER.ID.eq(WALLET_DETAIL.USER_ID)).where(
                    USER.PARENT_ID.eq(userId).or(USER.ID.eq(userId))
            );
            if (RegexUtil.checkObjectIsNotNull(targetUserId)) {
                queryChain.eq(WalletDetail::getUserId, targetUserId);
            }
        } else {
            queryChain.eq(WalletDetail::getUserId, userId);
        }
        if (RegexUtil.checkObjectIsNotNull(useFlag)) {
            queryChain.eq(WalletDetail::getUseFlag, useFlag);
        }
        if (RegexUtil.checkStringIsNotNull(cardNumber)) {
            queryChain.like(WalletDetail::getCardNumber, cardNumber);
        }
        if (RegexUtil.checkStringIsNotNull(orderId)) {
            queryChain.like(WalletDetail::getOrderId, orderId);
        }
        if (RegexUtil.checkObjectIsNotNull(startDate)) {
            queryChain.ge(WalletDetail::getRequestDate, DateUtil.getDayBeginDate(startDate, "yyyy-MM-dd"));
        }
        if (RegexUtil.checkObjectIsNotNull(endDate)) {
            queryChain.le(WalletDetail::getRequestDate, DateUtil.getDayEndDate(endDate, "yyyy-MM-dd"));
        }
        if (RegexUtil.checkObjectIsNotNull(remark)) {
            queryChain.like(WalletDetail::getRemark, remark);
        }
        queryChain.orderBy(WalletDetail::getRequestDate, false);
        return queryChain.page(pageable);
    }

    @Override
    public Page<WalletDetailVoBoss> paging(
            Page<WalletDetailVoBoss> pageable,
            Long targetUserId,
            String cardNumber,
            Integer useFlag,
            String startDate,
            String endDate,
            String remark,
            Long dealerId) {
        QueryChain<WalletDetail> queryChain = queryChain();
        queryChain.leftJoin(USER.as("user")).on(USER.ID.eq(WALLET_DETAIL.USER_ID));
        queryChain.select(WALLET_DETAIL.ALL_COLUMNS)
                .select(USER.EMAIL.as("account"));
        queryChain.leftJoin(BOSS_USER.as("dealer")).on(USER.BE_LONG_TO_DEALER.eq(BOSS_USER.ID));
        queryChain.select(BOSS_USER.EMAIL.as("dealerAccount"));
        if (!BossUserUtil.hasAllData()) {
            Long bossUserId = BossUserUtil.getId();
            queryChain.and(
                    BOSS_USER.as("dealer").ID.eq(bossUserId)
                            .or(BOSS_USER.as("dealer").PARENT_ID.eq(bossUserId))
            );
        } else {
            if (RegexUtil.checkObjectIsNotNull(dealerId)) {
                queryChain.and(
                        BOSS_USER.as("dealer").ID.eq(dealerId)
                                .or(BOSS_USER.as("dealer").PARENT_ID.eq(dealerId))
                );
            }
        }
        if (RegexUtil.checkObjectIsNotNull(targetUserId)) {
            queryChain.eq(WalletDetail::getUserId, targetUserId);
        }
        if (RegexUtil.checkStringIsNotNull(cardNumber)) {
            queryChain.like(WalletDetail::getCardNumber, cardNumber);
        }
        if (RegexUtil.checkObjectIsNotNull(useFlag)) {
            queryChain.eq(WalletDetail::getUseFlag, useFlag);
        }
        if (RegexUtil.checkObjectIsNotNull(startDate)) {
            queryChain.ge(WalletDetail::getRequestDate, DateUtil.getDayBeginDate(startDate, "yyyy-MM-dd"));
        }
        if (RegexUtil.checkObjectIsNotNull(endDate)) {
            queryChain.le(WalletDetail::getRequestDate, DateUtil.getDayEndDate(endDate, "yyyy-MM-dd"));
        }
        if (RegexUtil.checkObjectIsNotNull(remark)) {
            queryChain.like(WalletDetail::getRemark, remark);
        }
        queryChain.orderBy(WalletDetail::getRequestDate, false);

        return pageAs(pageable, queryChain, WalletDetailVoBoss.class);
    }

    @Override
    public Boolean updateStatusByOrderId(String orderId) {
        return updateChain()
                .eq(WalletDetail::getOrderId, orderId)
                .update();
    }

    @Override
    public Boolean updateStatusAndWalletAmountByOrderId(BigDecimal walletAmount, String orderId) {
        return updateChain()
                .set(WalletDetail::getWalletAmount, walletAmount)
                .eq(WalletDetail::getOrderId, orderId)
                .update();
    }

    @Override
    public Boolean updateStatusAndWalletAmountById(BigDecimal walletAmount, Long id) {
        return updateChain()
                .set(WalletDetail::getWalletAmount, walletAmount)
                .eq(WalletDetail::getId, id)
                .update();
    }

    @Override
    public List<WalletDetail> listByOrderId(String orderId) {
        return queryChain().eq(WalletDetail::getOrderId, orderId).list();
    }

    @Override
    public Boolean setCardNumberAndCardNUmberId(String orderId, String cardNumber, Long cardNumberId) {
        return updateChain()
                .set(WalletDetail::getCardNumber, cardNumber)
                .set(WalletDetail::getUserCardId, cardNumberId)
                .eq(WalletDetail::getOrderId, orderId)
                .update();
    }

    private WalletDetail baseEntity(Integer useFlag, String cardNumber, String orderId, String remark, BigDecimal
            amount, BigDecimal walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = new WalletDetail();
        walletDetail.setOrderId(orderId);
        walletDetail.setCardNumber(cardNumber);
        walletDetail.setUseFlag(useFlag);
        walletDetail.setRemark(remark);
        walletDetail.setAmount(amount);
        walletDetail.setWalletAmount(walletAmount);
        walletDetail.setCurrencyId(currencyId);
        walletDetail.setUserId(userId);
        walletDetail.setRequestDate(new Date());
        try {
            HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
            walletDetail.setRequestIp(IpUtil.getIp(request));
        } catch (Exception e) {
            walletDetail.setRequestIp("");
        }
        return walletDetail;
    }

    @Override
    public WalletDetail openCard(
            Long cardTypeId,
            String channel,
            String orderId, String remark, BigDecimal amount, BigDecimal
                    walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(0, "", orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setCardTypeId(cardTypeId);
        walletDetail.setChannel(channel);
        walletDetail.setHasTransferIn(false);
        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail recharge(Long userCardId,
                                 Long cardTypeId,
                                 String channel,
                                 String cardNumber, String orderId, String remark, BigDecimal amount, BigDecimal
                                         walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(1, cardNumber, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setCardTypeId(cardTypeId);
        walletDetail.setUserCardId(userCardId);
        walletDetail.setChannel(channel);
        walletDetail.setHasTransferIn(false);
        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail rechargeServiceCharge(Long userCardId,
                                              Long cardTypeId,
                                              String channel,
                                              String cardNumber, String orderId, String remark, BigDecimal
                                                      amount, BigDecimal walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(6, cardNumber, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setCardTypeId(cardTypeId);
        walletDetail.setUserCardId(userCardId);
        walletDetail.setChannel(channel);
        walletDetail.setHasTransferIn(false);

        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail out(Long userCardId,
                            Long cardTypeId,
                            String channel,
                            String cardNumber, String orderId, String remark, BigDecimal amount, BigDecimal
                                    walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(2, cardNumber, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setCardTypeId(cardTypeId);
        walletDetail.setUserCardId(userCardId);
        walletDetail.setChannel(channel);
        walletDetail.setHasTransferIn(true);

        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail accountRecharge(String orderId, String remark, BigDecimal amount, BigDecimal
            walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(3, null, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setHasTransferIn(true);

        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail accountWithdraw(String orderId, String remark, BigDecimal amount, BigDecimal walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(4, null, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setHasTransferIn(false);

        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail accountOut(String orderId, String remark, BigDecimal amount, BigDecimal
            walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(4, null, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setHasTransferIn(false);

        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail transferIn(String orderId, String remark, BigDecimal amount, BigDecimal walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(21, null, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setHasTransferIn(true);
        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail transferOut(String orderId, String remark, BigDecimal amount, BigDecimal walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(22, null, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setHasTransferIn(false);

        save(walletDetail);
        return walletDetail;
    }


    @Override
    public WalletDetail accountRegulation(
            String orderId,
            String remark,
            BigDecimal amount,
            BigDecimal walletAmount,
            Long currencyId,
            Long userId,
            Boolean hasTransferIn
    ) {
        WalletDetail walletDetail = baseEntity(16, null, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setHasTransferIn(hasTransferIn);
        save(walletDetail);
        return walletDetail;
    }


    @Override
    public WalletDetail cardRegulation(
            String orderId,
            String remark,
            BigDecimal amount,
            BigDecimal walletAmount,
            Long currencyId,
            Long userId,
            Boolean hasTransferIn) {
        WalletDetail walletDetail = baseEntity(17, null, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setHasTransferIn(hasTransferIn);
        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail authFee(Long userCardId, Long cardTypeId, String channel, String cardNumber, String orderId, String remark, BigDecimal amount, BigDecimal walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(23, cardNumber, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setCardTypeId(cardTypeId);
        walletDetail.setUserCardId(userCardId);
        walletDetail.setChannel(channel);
        walletDetail.setHasTransferIn(false);
        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail authMinFee(Long userCardId, Long cardTypeId, String channel, String cardNumber, String orderId, String remark, BigDecimal amount, BigDecimal walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(24, cardNumber, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setCardTypeId(cardTypeId);
        walletDetail.setUserCardId(userCardId);
        walletDetail.setChannel(channel);
        walletDetail.setHasTransferIn(false);

        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail failFee(Long userCardId, Long cardTypeId, String channel, String cardNumber, String orderId, String remark, BigDecimal amount, BigDecimal walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(25, cardNumber, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setCardTypeId(cardTypeId);
        walletDetail.setUserCardId(userCardId);
        walletDetail.setChannel(channel);
        walletDetail.setHasTransferIn(false);

        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail reversalFee(Long userCardId, Long cardTypeId, String channel, String cardNumber, String orderId, String remark, BigDecimal amount, BigDecimal walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(26, cardNumber, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setCardTypeId(cardTypeId);
        walletDetail.setUserCardId(userCardId);
        walletDetail.setChannel(channel);
        walletDetail.setHasTransferIn(false);

        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail refundFee(Long userCardId, Long cardTypeId, String channel, String cardNumber, String orderId, String remark, BigDecimal amount, BigDecimal walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(27, cardNumber, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setCardTypeId(cardTypeId);
        walletDetail.setUserCardId(userCardId);
        walletDetail.setChannel(channel);
        walletDetail.setHasTransferIn(false);

        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail crossBorderFee(Long userCardId, Long cardTypeId, String channel, String cardNumber, String orderId, String remark, BigDecimal amount, BigDecimal walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(28, cardNumber, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setCardTypeId(cardTypeId);
        walletDetail.setUserCardId(userCardId);
        walletDetail.setChannel(channel);
        walletDetail.setHasTransferIn(false);

        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail shareAccountRecharge(Long shareAccountId, String orderId, String remark, BigDecimal amount, BigDecimal walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(29, null, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setHasTransferIn(false);

        save(walletDetail);
        return walletDetail;
    }

    @Override
    public WalletDetail shareAccountWithdraw(Long shareAccountId, String orderId, String remark, BigDecimal amount, BigDecimal walletAmount, Long currencyId, Long userId) {
        WalletDetail walletDetail = baseEntity(30, null, orderId, remark, amount, walletAmount, currencyId, userId);
        walletDetail.setHasTransferIn(true);

        save(walletDetail);
        return walletDetail;
    }

    @Override
    public BigDecimal sumAmountByUserId(Long userId, Integer useFlag) {
        BigDecimal bigDecimal = mapper.sumAmountByUserId(userId, useFlag);
        if (bigDecimal == null) {
            return BigDecimal.ZERO;
        }
        if (bigDecimal.compareTo(BigDecimal.ZERO) < 0) {
            return BigDecimal.ZERO;
        }
        return bigDecimal;
    }


}
